/*	
*	File: pcraft-tool.cpp
*	Date: 2011/11/07
*	User: Ronmaru
*	Desctiption: pcraft-tool functions realizations
*/

#include "pcraft-tool.h"
#include <fstream>

int WriteDevicesList(const std::string &file_name)
{
  ofstream out_file(file_name);
  int num_devices = 0;
  char errbuf_[PCAP_ERRBUF_SIZE];
  pcap_if_t *devlist_;
  pcap_if_t *curdev_;
  if (pcap_findalldevs(&devlist_, errbuf_) == -1) { 
    std::cout << "Error finding devices: " << errbuf_ << std::endl;
  } else {
    for (curdev_ = devlist_; curdev_; curdev_ = curdev_->next) { 
      ++num_devices;
      out_file << curdev_->name << std::endl;
    }
  }
  out_file.close();

  return num_devices;
}

ETHERNETheader MakeEthernetHeader(const boost::program_options::variables_map &var_map)
{
  ETHERNETheader ethernet_header;
  ethernet_header.SetDestinationMac(MacAddress(var_map["ethernet-destination"].as<string>()));
  ethernet_header.SetSourceMac(MacAddress(var_map["ethernet-source"].as<string>()));
  ethernet_header.SetType(var_map["ethernet-type"].as<int>());

  return ethernet_header;
}

IPV4header MakeIpv4Header(const boost::program_options::variables_map &var_map)
{
  IPV4header ipv4_header;
  ipv4_header.SetVersion(var_map["ipv4-version"].as<int>());
  ipv4_header.SetHeaderLength(var_map["ipv4-header-length"].as<int>());
  ipv4_header.SetTypeOfService(var_map["ipv4-type-of-service"].as<int>());
  ipv4_header.SetTotalLength(var_map["ipv4-total-length"].as<int>());
  ipv4_header.SetIdentification(var_map["ipv4-identification"].as<int>());
  ipv4_header.SetDontFragment(var_map["ipv4-dont-fragment"].as<int>());
  ipv4_header.SetMoreFragments(var_map["ipv4-more-fragments"].as<int>());
  ipv4_header.SetFragmentOffset(var_map["ipv4-fragment-offset"].as<int>());
  ipv4_header.SetTimeToLive(var_map["ipv4-ttl"].as<int>());
  ipv4_header.SetProtocol(var_map["ipv4-protocol"].as<int>());
  ipv4_header.SetSourceAddress(boost::asio::ip::address_v4::from_string(var_map["ipv4-source-addr"].as<std::string>().c_str()));
  ipv4_header.SetDestinationAddress(boost::asio::ip::address_v4::from_string(var_map["ipv4-dest-addr"].as<std::string>().c_str()));
  ipv4_header.ComputeChecksum();

  return ipv4_header;
}

ICMPheader MakeIcmpHeader(const boost::program_options::variables_map &var_map)
{
  ICMPheader icmp_header;
  icmp_header.SetType(var_map["icmp-type"].as<int>());
  icmp_header.SetCode(var_map["icmp-code"].as<int>());
  icmp_header.SetIdentifier(var_map["icmp-identifier"].as<int>());
  icmp_header.SetSequenceNumber(var_map["icmp-sequence-number"].as<int>());

  return icmp_header;
}

UDPheader MakeUdpHeader(const boost::program_options::variables_map &var_map)
{
  UDPheader udp_header;
  udp_header.SetSourcePort(var_map["udp-source-port"].as<int>());
  udp_header.SetDestinationPort(var_map["udp-dest-port"].as<int>());
  udp_header.SetMessageLength(var_map["udp-message-length"].as<int>());

  return udp_header;
}


UDPpseudoheader MakeUdpPseudoHeader(const boost::program_options::variables_map &var_map)
{
  UDPpseudoheader udp_pseudo_header;
  udp_pseudo_header.SetSourceAddress(boost::asio::ip::address_v4::from_string(var_map["ipv4-source-addr"].as<std::string>().c_str()));
  udp_pseudo_header.SetDestinationAddress(boost::asio::ip::address_v4::from_string(var_map["ipv4-dest-addr"].as<std::string>().c_str()));
  udp_pseudo_header.SetMessageProtocol();
  udp_pseudo_header.SetDatagramLength(var_map["udp-message-length"].as<int>());

  return udp_pseudo_header;
}

IGMPv2header MakeIgmpv2Header(const boost::program_options::variables_map &var_map)
{
  IGMPv2header igmpv2_header;
  igmpv2_header.SetType(var_map["igmpv2-type"].as<int>());
  igmpv2_header.SetMaxRespTime(var_map["igmpv2-max-resp-time"].as<int>());
  igmpv2_header.SetGroupAddress(boost::asio::ip::address_v4::from_string(var_map["igmpv2-group-address"].as<std::string>().c_str()));

  return igmpv2_header;
}

ARPheader MakeArpHeader(const boost::program_options::variables_map &var_map)
{
  ARPheader arp_header;
  arp_header.SetHTYPE(var_map["arp-hardware-type"].as<int>());
  arp_header.SetPTYPE(var_map["arp-protocol-type"].as<int>());
  arp_header.SetHLEN(var_map["arp-hardware-length"].as<int>());
  arp_header.SetPLEN(var_map["arp-protocol-length"].as<int>());
  arp_header.SetOPER(var_map["arp-operation"].as<int>());
  arp_header.SetSHA(MacAddress(var_map["arp-sender-haddr"].as<string>()));
  arp_header.SetSPA(boost::asio::ip::address_v4::from_string(var_map["arp-sender-paddr"].as<std::string>().c_str()));
  arp_header.SetTHA(MacAddress(var_map["arp-target-haddr"].as<string>()));
  arp_header.SetTPA(boost::asio::ip::address_v4::from_string(var_map["arp-target-paddr"].as<std::string>().c_str()));

  return arp_header;
}

TCPheader MakeTcpHeader(const boost::program_options::variables_map &var_map)
{
  TCPheader tcp_header;
  tcp_header.SetSourcePort(var_map["tcp-source-port"].as<int>());
  tcp_header.SetDestinationPort(var_map["tcp-dest-port"].as<int>());
  tcp_header.SetSequenceNumber(var_map["tcp-seq-number"].as<int>());
  tcp_header.SetAcknoledgmentNumber(var_map["tcp-ack-number"].as<int>());
  tcp_header.SetDataOffset(var_map["tcp-data-offset"].as<int>());
  tcp_header.SetURG(var_map["tcp-urg"].as<bool>());
  tcp_header.SetACK(var_map["tcp-ack"].as<bool>());
  tcp_header.SetPSH(var_map["tcp-ack"].as<bool>());
  tcp_header.SetRST(var_map["tcp-rst"].as<bool>());
  tcp_header.SetSYN(var_map["tcp-syn"].as<bool>());
  tcp_header.SetFIN(var_map["tcp-fin"].as<bool>());
  tcp_header.SetWindow(var_map["tcp-window"].as<int>());
  tcp_header.SetUrgentPoint(var_map["tcp-urgent-point"].as<int>());

  return tcp_header;
}

TCPpseudoheader MakeTcpPseudoHeader(const boost::program_options::variables_map &var_map)
{
  TCPpseudoheader tcp_pseudo_header;
  tcp_pseudo_header.SetSourceAddress(boost::asio::ip::address_v4::from_string(var_map["ipv4-source-addr"].as<std::string>().c_str()));
  tcp_pseudo_header.SetDestinationAddress(boost::asio::ip::address_v4::from_string(var_map["ipv4-dest-addr"].as<std::string>().c_str()));
  tcp_pseudo_header.SetMessageProtocol();
  tcp_pseudo_header.SetDatagramLength(var_map["tcp-message-length"].as<int>());

  return tcp_pseudo_header;
}

RIPheader MakeRipHeader(const boost::program_options::variables_map &var_map)
{
  RIPheader rip_header;
  rip_header.SetCommand(var_map["rip-command"].as<int>());
  rip_header.SetVersion();
  rip_header.SetRoutingDomain(var_map["rip-routing-domain"].as<int>());
  rip_header.SetAFIdent(var_map["rip-af-ident"].as<int>());
  rip_header.SetRouteTag(var_map["rip-route-tag"].as<int>());
  rip_header.SetIPAddr(boost::asio::ip::address_v4::from_string(var_map["rip-ip-addr"].as<std::string>().c_str()));
  rip_header.SetMask(boost::asio::ip::address_v4::from_string(var_map["rip-mask"].as<std::string>().c_str()));
  rip_header.SetNextHop(boost::asio::ip::address_v4::from_string(var_map["rip-next-hop"].as<std::string>().c_str()));
  rip_header.SetMetric(var_map["rip-metric"].as<int>());

  return rip_header;
}